#include <assert.h>
#include <WinSock2.h>
#include <map>
#include <assert.h>
#include <iostream>

#include "Interface.h"
#include "TcpServer.h"

/*
using namespace std;

//===========================================================================
int Socket::nofSockets_= 0;

//===========================================================================
void Socket::Start( void )
{
    if( !nofSockets_ ) {
        WSADATA info;
        if( WSAStartup( MAKEWORD( 2, 0 ), &info ) ) {
            throw "Could not start WSA";
        }
    }
    
    ++nofSockets_;
}

//===========================================================================
void Socket::End( void ) {
    WSACleanup();
}

//===========================================================================
Socket::Socket( void )
    : s_( 0 )
{
    Start();
    this->s_ = ::socket( AF_INET, SOCK_STREAM, 0 );
    assert( INVALID_SOCKET != this->s_ );

    refCounter_ = new int( 1 );
}

//===========================================================================
Socket::Socket(
    SOCKET s
)   : s_( s )
{
    Socket::Start();
    refCounter_ = new int( 1 );
};

//===========================================================================
Socket::~Socket() {
    if( ! --( *refCounter_ ) ) {
        this->Close();
        delete this->refCounter_;
        this->refCounter_ = NULL;
    }

  --nofSockets_;
  if( !nofSockets_ )
      Socket::End();
}

//===========================================================================
Socket::Socket(
    const Socket & o
) {
    refCounter_ = o.refCounter_;
    ( *refCounter_ )++;
    s_ = o.s_;

    nofSockets_++;
}

//===========================================================================
Socket & Socket::operator = (
    Socket & o
) {
  ( *o.refCounter_ )++;

  refCounter_ = o.refCounter_;
  s_          = o.s_;
  nofSockets_++;

  return *this;
}

//===========================================================================
void Socket::Close( void ) {
    closesocket( this->s_ );
}

//===========================================================================
std::string Socket::ReceiveBytes( void ) {
    std::string ret;
    char buf[ 1024 ] = { 0, };
 
    while( true ) {
        u_long arg = 0;
        if( ioctlsocket( s_, FIONREAD, &arg ) != 0 )
            break;

        if( arg == 0 )
            break;

        if( arg > 1024 )
            arg = 1024;

        int rv = recv( s_, buf, arg, 0 );
        if( rv <= 0 )
            break;

        std::string t;

        t.assign( buf, rv );
        ret += t;
    }
 
    return ret;
}

//===========================================================================
std::string Socket::ReceiveLine( void ) {
    std::string ret;
    while( true ) {
        char r;

        switch( recv( s_, &r, 1, 0 ) ) {
            case 0  : return ret;
            case -1 : return "";
        }

        ret += r;
        if( r == '\n' )
            return ret;
    }
}

//===========================================================================
void Socket::SendLine(
    std::string s
) {
    s += '\n';
    send( s_, s.c_str(), s.length(), 0 );
}

//===========================================================================
void Socket::SendBytes(
    const std::string & s
) {
    send( s_, s.c_str(), s.length(), 0 );
}

//===========================================================================
SocketServer::SocketServer(
    int port,
    int connections
) {
    sockaddr_in sa;
    memset( &sa, 0, sizeof( sa ) );

    sa.sin_family = PF_INET;             
    sa.sin_port   = htons( port );
    s_ = socket( AF_INET, SOCK_STREAM, 0 );
    assert( s_ != INVALID_SOCKET );

    u_long arg = 1;
    ioctlsocket( s_, FIONBIO, &arg );

    if( bind( s_, ( sockaddr * )&sa, sizeof( sockaddr_in ) ) == SOCKET_ERROR ) {
        closesocket( s_ );
        throw "INVALID_SOCKET";
    }
  
    listen( s_, connections );
}

//===========================================================================
Socket* SocketServer::Accept( void ) {
    SOCKET new_sock = accept( s_, 0, 0 );
    if( new_sock == INVALID_SOCKET ) {
        int rc = WSAGetLastError();
        if( rc == WSAEWOULDBLOCK ) {
            return 0; // non-blocking call, no request pending
        }
        else {
            throw "Invalid Socket";
        }
    }

    Socket * r = new Socket( new_sock );
    return r;
}

//===========================================================================
SocketClient::SocketClient(
    const std::string & host,
          int           port
)   : Socket()
{
    std::string error;

    hostent * he;
    if( ( he = gethostbyname( host.c_str() ) ) == 0 ) {
        assert( he != 0 );
    }

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port   = htons( port );
    addr.sin_addr   = *( ( in_addr * )he->h_addr );
    memset( &( addr.sin_zero ), 0, 8 ); 

    if( ::connect( s_, ( sockaddr * )&addr, sizeof( sockaddr ) ) ) {
        assert( true );
        throw error;
    }
}

//===========================================================================
SocketSelect::SocketSelect(
    Socket const * const s1,
    Socket const * const s2
) {
    FD_ZERO( &fds_ );
    FD_SET( const_cast< Socket * >( s1 )->s_, &fds_ );
    if( s2 )
        FD_SET( const_cast< Socket * >( s2 )->s_, &fds_ );

    TIMEVAL tval;
    tval.tv_sec  = 0;
    tval.tv_usec = 1;

    if( select( 0, &fds_, ( fd_set * ) 0, ( fd_set * ) 0, &tval ) == SOCKET_ERROR )
        throw "Error in select";
}

//===========================================================================
bool SocketSelect::Readable(
    Socket const * const s
) {
    return FD_ISSET( s->s_, &fds_ )
         ? true
         : false;
}
*/


/*
//===========================================================================
// If you need a bigger size buffer, please adjust this value.
// I can implement better socket buffer class, but I have no much time to complete this homework.
static const unsigned int BUFFER_SIZE = 1024;

//===========================================================================
// SocketBuffer
//===========================================================================
class SocketBuffer
{
public :

    SocketBuffer( void )
        : m_position( 0 )
    {}
    
    ~SocketBuffer( void ) {}

    bool Append(
        void *       data,
        unsigned int size
    ) {
        if( this->m_position + size > BUFFER_SIZE )
            return false;
        
        ::memcpy_s(
            this->m_buffer,
            BUFFER_SIZE - this->m_position,
            data,
            size
        );
        
        return true;
    }

    void Drain(
        unsigned int size
    ) {
        assert( size <= this->m_position );

        if( size == this->m_position ) {
            this->m_position = 0;
            return;
        }

        ::memcpy_s(
            this->m_buffer,
            BUFFER_SIZE,
            this->m_buffer + size,
            this->m_position - size
        );
        this->m_position -= size;
    }

private :

    char         m_buffer[ BUFFER_SIZE ];
    unsigned int m_position;    
};

//===========================================================================
// TcpServer
//===========================================================================
class TcpServer
{
public :

    TcpServer( void )
        : m_server( NULL )
    {
        WSADATA wsa;
        int result = ::WSAStartup( MAKEWORD( 2, 2 ), &wsa );
        assert( !result );
    }

    ~TcpServer( void ) {
        ::WSACleanup();
    }

    void Initizliae(
        ITcpServer * server,
        unsigned int port
    ) {
        assert( server );
        assert( !this->m_server );

        this->m_server = server;
        this->m_port   = port;
    }

    bool Run( void ) {
        SOCKET sock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
        if( INVALID_SOCKET == sock )
            return false;

        sockaddr_in address;
        address.sin_family      = AF_INET;
        address.sin_port        = htons( this->m_port );
        address.sin_addr.s_addr = inet_addr( "127.0.0.1" );

        int binded = ::bind(
            sock,
            ( SOCKADDR * )&address,
            sizeof( address )
        );
        if( SOCKET_ERROR == binded )
            return false;

        if( SOCKET_ERROR == ::listen( sock, 10 ) )
            return false;

        this->AcceptClients();
        return true;
    }
    
    void Cleanup( void ) {
        this->m_server = NULL;
    }

private :

    typedef std::map< SOCKET, SocketBuffer * > Clients;

    ITcpServer * m_server;
    unsigned int m_port;
    Clients      m_clients;

    void AcceptClients( void ) {
        sockaddr_in client;
        int len = sizeof( client );

        while( true ) {
            cSock = accept(sSock,(SOCKADDR*)&from,&fromlen);
            sprintf(temp,"Your IP address is %sn",inet_ntoa(from.sin_addr));
            send(cSock,temp,strlen(temp),0);
            std::cout << "Connection from " << inet_ntoa(from.sin_addr) <<"n";
            closesocket(cSock);
        }
    }
    
};

//===========================================================================
static TcpServer s_server;

//===========================================================================
bool InitializeTcpServer(
    ITcpServer * server,
    unsigned int port
) {
    s_server.Initizliae(
        server,
        port
    );
    
    return true;
}
*/